package db

import (
	"context"
	"data-system/config"
	"errors"
	"fmt"
	"log"
	"reflect"
	"time"

	"os"
	"os/exec"
	"path/filepath"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"go.mongodb.org/mongo-driver/mongo/readpref"
)

func Load() {
	go func() {
		//1. 生成配置
		cfg := config.Cfg()
		time.Sleep(1 * time.Second)
		dir, err := os.Getwd()
		if err != nil {
			log.Fatal(err)
		}
		configTempUri := filepath.Join(dir, "db/mongo.yml")
		configUri := filepath.Join(dir, "db/config.yml")
		bytes, err := os.ReadFile(configTempUri)
		configContent := fmt.Sprintf(string(bytes), cfg.MongoLogDir+"/mongo.log", cfg.MongoDataDir)
		err = os.WriteFile(configUri, []byte(configContent), 0755)
		// 2. 创建要执行的命令
		//cmd := exec.Command("./mongod --port=27018 --dbpath=e:/db/data --serviceName=mongo") //, " --logpath=e:/db/log/mongo.log") // Windows 下通常使用 mongod.exe
		command := exec.Command("taskkill", "/F", "/IM", "mongod.exe")
		err = command.Run()
		cmd := exec.Command("./mongod", "--config="+configUri)
		// 3. !!!核心步骤!!! 为命令指定工作目录
		cmd.Dir = dir + "/mongodb-8.0.13/bin"
		// 4. 捕获命令的输出和错误
		//err = cmd.Run()
		err = cmd.Run()
		if err != nil {
			log.Fatalf("执行命令失败: %v", err)
		}
	}()
}

var mongoClient *Mongo

func MongoClient() *Mongo {
	if mongoClient == nil {
		cfg := config.Cfg()
		newMongo, err := NewMongo(cfg.MongoUri, cfg.MongoDataBase)
		if err != nil {
			log.Printf("连接mongo异常：%v", err.Error())
		} else {
			mongoClient = newMongo
		}
	}
	return mongoClient
}

// Mongo MongoDB 操作工具类
type Mongo struct {
	client   *mongo.Client
	database string
}

// NewMongo 创建 MongoDB 工具实例
func NewMongo(uri, database string) (*Mongo, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri))
	if err != nil {
		return nil, fmt.Errorf("failed to connect to MongoDB: %v", err)
	}
	// 检查连接
	ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()
	if err = client.Ping(ctx, readpref.Primary()); err != nil {
		return nil, fmt.Errorf("failed to ping MongoDB: %v", err)
	}
	return &Mongo{
		client:   client,
		database: database,
	}, nil
}

// Close 关闭 MongoDB 连接
func (m *Mongo) Close() error {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	return m.client.Disconnect(ctx)
}

// getCollection 获取集合
func (m *Mongo) getCollection(collection string) *mongo.Collection {
	return m.client.Database(m.database).Collection(collection)
}

// InsertOne 插入单个文档
func (m *Mongo) InsertOne(document interface{}) (string, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	result, err := m.getCollection(GetCollection()).InsertOne(ctx, document)
	if err != nil {
		return "", fmt.Errorf("failed to insert document: %v", err)
	}
	if oid, ok := result.InsertedID.(primitive.ObjectID); ok {
		return oid.Hex(), nil
	}
	return "", errors.New("failed to get inserted ID")
}

// InsertMany 批量插入文档
func (m *Mongo) InsertMany(documents []interface{}) ([]string, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	result, err := m.getCollection(GetCollection()).InsertMany(ctx, documents)
	if err != nil {
		return nil, fmt.Errorf("failed to insert documents: %v", err)
	}
	var ids []string
	for _, id := range result.InsertedIDs {
		if oid, ok := id.(primitive.ObjectID); ok {
			ids = append(ids, oid.Hex())
		}
	}
	return ids, nil
}

// FindOne 查询单个文档
func (m *Mongo) FindOne(filter interface{}, result interface{}) error {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	err := m.getCollection(GetCollection()).FindOne(ctx, filter).Decode(result)
	if err != nil {
		if errors.Is(err, mongo.ErrNoDocuments) {
			return fmt.Errorf("document not found")
		}
		return fmt.Errorf("failed to find document: %v", err)
	}
	return nil
}

// FindMany 查询多个文档
func (m *Mongo) FindMany(filter interface{}, results interface{}, opts ...*options.FindOptions) error {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	cur, err := m.getCollection(GetCollection()).Find(ctx, filter, opts...)
	if err != nil {
		return fmt.Errorf("failed to find documents: %v", err)
	}
	defer func() {
		if err := cur.Close(ctx); err != nil {
			log.Printf("Failed to close cursor: %v", err)
		}
	}()
	// 使用反射创建切片
	resultv := reflect.ValueOf(results)
	if resultv.Kind() != reflect.Ptr || resultv.Elem().Kind() != reflect.Slice {
		return errors.New("results argument must be a pointer to a slice")
	}
	slicev := resultv.Elem()
	slicev = slicev.Slice(0, slicev.Cap())
	elemt := slicev.Type().Elem()

	for cur.Next(ctx) {
		elemp := reflect.New(elemt)
		if err := cur.Decode(elemp.Interface()); err != nil {
			return fmt.Errorf("failed to decode document: %v", err)
		}
		slicev = reflect.Append(slicev, elemp.Elem())
	}
	if err := cur.Err(); err != nil {
		return fmt.Errorf("cursor error: %v", err)
	}
	resultv.Elem().Set(slicev)
	return nil
}

// UpdateOne 更新单个文档
func (m *Mongo) UpdateOne(filter, update interface{}) (int64, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	result, err := m.getCollection(GetCollection()).UpdateOne(ctx, filter, update)
	if err != nil {
		return 0, fmt.Errorf("failed to update document: %v", err)
	}
	return result.ModifiedCount, nil
}

// UpdateMany 更新多个文档
func (m *Mongo) UpdateMany(filter, update interface{}) (int64, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	result, err := m.getCollection(GetCollection()).UpdateMany(ctx, filter, update)
	if err != nil {
		return 0, fmt.Errorf("failed to update documents: %v", err)
	}
	return result.ModifiedCount, nil
}

// ReplaceOne 替换单个文档
func (m *Mongo) ReplaceOne(filter, replacement interface{}) (int64, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	result, err := m.getCollection(GetCollection()).ReplaceOne(ctx, filter, replacement)
	if err != nil {
		return 0, fmt.Errorf("failed to replace document: %v", err)
	}
	return result.ModifiedCount, nil
}

// DeleteOne 删除单个文档
func (m *Mongo) DeleteOne(filter interface{}) (int64, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	result, err := m.getCollection(GetCollection()).DeleteOne(ctx, filter)
	if err != nil {
		return 0, fmt.Errorf("failed to delete document: %v", err)
	}
	return result.DeletedCount, nil
}

// DeleteMany 删除多个文档
func (m *Mongo) DeleteMany(filter interface{}) (int64, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	result, err := m.getCollection(GetCollection()).DeleteMany(ctx, filter)
	if err != nil {
		return 0, fmt.Errorf("failed to delete documents: %v", err)
	}
	return result.DeletedCount, nil
}

// CountDocuments 统计文档数量
func (m *Mongo) CountDocuments(filter interface{}) (int64, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	count, err := m.getCollection(GetCollection()).CountDocuments(ctx, filter)
	if err != nil {
		return 0, fmt.Errorf("failed to count documents: %v", err)
	}
	return count, nil
}

// Aggregate 聚合查询
func (m *Mongo) Aggregate(pipeline interface{}, results interface{}) error {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	cur, err := m.getCollection(GetCollection()).Aggregate(ctx, pipeline)
	if err != nil {
		return fmt.Errorf("failed to aggregate: %v", err)
	}
	defer func() {
		if err := cur.Close(ctx); err != nil {
			log.Printf("Failed to close cursor: %v", err)
		}
	}()
	// 使用反射创建切片
	resultv := reflect.ValueOf(results)
	if resultv.Kind() != reflect.Ptr || resultv.Elem().Kind() != reflect.Slice {
		return errors.New("results argument must be a pointer to a slice")
	}
	slicev := resultv.Elem()
	slicev = slicev.Slice(0, slicev.Cap())
	elemt := slicev.Type().Elem()
	for cur.Next(ctx) {
		elemp := reflect.New(elemt)
		if err := cur.Decode(elemp.Interface()); err != nil {
			return fmt.Errorf("failed to decode document: %v", err)
		}
		slicev = reflect.Append(slicev, elemp.Elem())
	}
	if err := cur.Err(); err != nil {
		return fmt.Errorf("cursor error: %v", err)
	}
	resultv.Elem().Set(slicev)
	return nil
}

// CreateIndex 创建索引
func (m *Mongo) CreateIndex(keys bson.D, unique bool) (string, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	index := mongo.IndexModel{
		Keys:    keys,
		Options: options.Index().SetUnique(unique),
	}
	name, err := m.getCollection(GetCollection()).Indexes().CreateOne(ctx, index)
	if err != nil {
		return "", fmt.Errorf("failed to create index: %v", err)
	}
	return name, nil
}

// ListIndexes 列出所有索引
func (m *Mongo) ListIndexes(collection string) ([]bson.M, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	cur, err := m.getCollection(GetCollection()).Indexes().List(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to list indexes: %v", err)
	}
	defer func() {
		if err := cur.Close(ctx); err != nil {
			log.Printf("Failed to close cursor: %v", err)
		}
	}()
	var indexes []bson.M
	if err := cur.All(ctx, &indexes); err != nil {
		return nil, fmt.Errorf("failed to decode indexes: %v", err)
	}
	return indexes, nil
}

// DropIndex 删除索引
func (m *Mongo) DropIndex(name string) error {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	_, err := m.getCollection(GetCollection()).Indexes().DropOne(ctx, name)
	if err != nil {
		return fmt.Errorf("failed to drop index: %v", err)
	}
	return nil
}

// BulkWrite 批量写入操作
func (m *Mongo) BulkWrite(operations []mongo.WriteModel) (*mongo.BulkWriteResult, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	result, err := m.getCollection(GetCollection()).BulkWrite(ctx, operations)
	if err != nil {
		return nil, fmt.Errorf("failed to bulk write: %v", err)
	}
	return result, nil
}

// FindOneAndUpdate 查找并更新单个文档
func (m *Mongo) FindOneAndUpdate(filter, update interface{}, result interface{}, opts ...*options.FindOneAndUpdateOptions) error {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	err := m.getCollection(GetCollection()).FindOneAndUpdate(ctx, filter, update, opts...).Decode(result)
	if err != nil {
		if errors.Is(err, mongo.ErrNoDocuments) {
			return fmt.Errorf("document not found")
		}
		return fmt.Errorf("failed to find and update document: %v", err)
	}
	return nil
}

// FindOneAndReplace 查找并替换单个文档
func (m *Mongo) FindOneAndReplace(filter, replacement interface{}, result interface{}, opts ...*options.FindOneAndReplaceOptions) error {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	err := m.getCollection(GetCollection()).FindOneAndReplace(ctx, filter, replacement, opts...).Decode(result)
	if err != nil {
		if errors.Is(err, mongo.ErrNoDocuments) {
			return fmt.Errorf("document not found")
		}
		return fmt.Errorf("failed to find and replace document: %v", err)
	}
	return nil
}

// FindOneAndDelete 查找并删除单个文档
func (m *Mongo) FindOneAndDelete(filter interface{}, result interface{}) error {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	err := m.getCollection(GetCollection()).FindOneAndDelete(ctx, filter).Decode(result)
	if err != nil {
		if errors.Is(err, mongo.ErrNoDocuments) {
			return fmt.Errorf("document not found")
		}
		return fmt.Errorf("failed to find and delete document: %v", err)
	}
	return nil
}

// Watch 监听集合变化
func (m *Mongo) Watch(pipeline interface{}, handler func(changeDoc bson.M)) error {
	ctx := context.Background()
	stream, err := m.getCollection(GetCollection()).Watch(ctx, pipeline)
	if err != nil {
		return fmt.Errorf("failed to watch collection: %v", err)
	}
	defer func() {
		if err := stream.Close(ctx); err != nil {
			log.Printf("Failed to close change stream: %v", err)
		}
	}()
	log.Println("Watching for changes...")
	for stream.Next(ctx) {
		var changeDoc bson.M
		if err := stream.Decode(&changeDoc); err != nil {
			return fmt.Errorf("failed to decode change document: %v", err)
		}
		handler(changeDoc)
	}
	if err := stream.Err(); err != nil {
		return fmt.Errorf("change stream error: %v", err)
	}
	return nil
}

func GetCollection() string {
	return config.Cfg().Project
}

//type User struct {
//	ID        primitive.ObjectID `bson:"_id,omitempty"`
//	Name      string             `bson:"name"`
//	Age       int                `bson:"age"`
//	Email     string             `bson:"email"`
//	CreatedAt time.Time          `bson:"created_at"`
//	UpdatedAt time.Time          `bson:"updated_at"`
//}
//
//type Post struct {
//	ID      primitive.ObjectID `bson:"_id,omitempty"`
//	UserID  primitive.ObjectID `bson:"user_id"`
//	Title   string             `bson:"title"`
//	Content string             `bson:"content"`
//	Tags    []string           `bson:"tags"`
//}
//
//func test() {
//	// 初始化 MongoDB 工具
//	mongoURI := "mongodb://localhost:27017"
//	dbName := "testdb"
//	collectionName := "users"
//	mongoUtil, err := NewMongo(mongoURI, dbName, collectionName)
//	if err != nil {
//		log.Fatalf("Failed to initialize MongoDB util: %v", err)
//	}
//	defer mongoUtil.Close()
//
//	// 1. 插入文档
//	user := User{
//		Name:      "张三",
//		Age:       30,
//		Email:     "zhangsan@example.com",
//		CreatedAt: time.Now(),
//		UpdatedAt: time.Now(),
//	}
//
//	insertedID, err := mongoUtil.InsertOne(user)
//	if err != nil {
//		log.Printf("Failed to insert user: %v", err)
//	} else {
//		log.Printf("Inserted user with ID: %s", insertedID)
//	}
//
//	// 批量插入
//	users := []interface{}{
//		User{
//			Name:      "李四",
//			Age:       25,
//			Email:     "lisi@example.com",
//			CreatedAt: time.Now(),
//			UpdatedAt: time.Now(),
//		},
//		User{
//			Name:      "王五",
//			Age:       28,
//			Email:     "wangwu@example.com",
//			CreatedAt: time.Now(),
//			UpdatedAt: time.Now(),
//		},
//	}
//
//	insertedIDs, err := mongoUtil.InsertMany(users)
//	if err != nil {
//		log.Printf("Failed to insert users: %v", err)
//	} else {
//		log.Printf("Inserted users with IDs: %v", insertedIDs)
//	}
//
//	// 2. 查询文档
//	// 查询单个文档
//	var foundUser User
//	err = mongoUtil.FindOne(bson.M{"name": "张三"}, &foundUser)
//	if err != nil {
//		log.Printf("Failed to find user: %v", err)
//	} else {
//		log.Printf("Found user: %+v", foundUser)
//	}
//
//	// 查询多个文档
//	var foundUsers []User
//	err = mongoUtil.FindMany(bson.M{"age": bson.M{"$gt": 25}}, &foundUsers)
//	if err != nil {
//		log.Printf("Failed to find users: %v", err)
//	} else {
//		log.Printf("Found %d users:", len(foundUsers))
//		for _, u := range foundUsers {
//			log.Printf("- %+v", u)
//		}
//	}
//
//	// 带分页和排序的查询
//	findOptions := options.Find()
//	findOptions.SetLimit(2)
//	findOptions.SetSkip(0)
//	findOptions.SetSort(bson.M{"age": -1}) // 按年龄降序
//
//	var pagedUsers []User
//	err = mongoUtil.FindMany(bson.M{}, &pagedUsers, findOptions)
//	if err != nil {
//		log.Printf("Failed to find paged users: %v", err)
//	} else {
//		log.Printf("Found %d paged users:", len(pagedUsers))
//		for _, u := range pagedUsers {
//			log.Printf("- %+v", u)
//		}
//	}
//
//	// 3. 更新文档
//	update := bson.M{
//		"$set": bson.M{
//			"age":        31,
//			"updated_at": time.Now(),
//		},
//	}
//
//	updatedCount, err := mongoUtil.UpdateOne(bson.M{"name": "张三"}, update)
//	if err != nil {
//		log.Printf("Failed to update user: %v", err)
//	} else {
//		log.Printf("Updated %d user", updatedCount)
//	}
//
//	// 更新多个文档
//	updatedCount, err = mongoUtil.UpdateMany(
//		bson.M{"age": bson.M{"$lt": 30}},
//		bson.M{"$inc": bson.M{"age": 1}},
//	)
//	if err != nil {
//		log.Printf("Failed to update users: %v", err)
//	} else {
//		log.Printf("Updated %d users", updatedCount)
//	}
//
//	// 4. 删除文档
//	deletedCount, err := mongoUtil.DeleteOne(bson.M{"name": "王五"})
//	if err != nil {
//		log.Printf("Failed to delete user: %v", err)
//	} else {
//		log.Printf("Deleted %d user", deletedCount)
//	}
//
//	// 5. 聚合查询
//	// 按年龄分组统计用户数
//	pipeline := []bson.M{
//		{
//			"$group": bson.M{
//				"_id":   "$age",
//				"count": bson.M{"$sum": 1},
//			},
//		},
//		{
//			"$sort": bson.M{"_id": 1},
//		},
//	}
//
//	var aggregationResults []bson.M
//	err = mongoUtil.Aggregate(pipeline, &aggregationResults)
//	if err != nil {
//		log.Printf("Failed to aggregate: %v", err)
//	} else {
//		log.Println("Age distribution:")
//		for _, result := range aggregationResults {
//			log.Printf("- Age %v: %v users", result["_id"], result["count"])
//		}
//	}
//
//	// 6. 索引操作
//	// 创建唯一索引
//	indexName, err := mongoUtil.CreateIndex(bson.D{{Key: "email", Value: 1}}, true)
//	if err != nil {
//		log.Printf("Failed to create index: %v", err)
//	} else {
//		log.Printf("Created index: %s", indexName)
//	}
//
//	// 列出所有索引
//	indexes, err := mongoUtil.ListIndexes()
//	if err != nil {
//		log.Printf("Failed to list indexes: %v", err)
//	} else {
//		log.Println("Collection indexes:")
//		for _, index := range indexes {
//			log.Printf("- %v", index["name"])
//		}
//	}
//
//	// 7. 使用不同集合
//	postUtil := mongoUtil.WithCollection("posts")
//
//	// 插入帖子
//	userID, _ := primitive.ObjectIDFromHex(insertedID)
//	post := Post{
//		UserID:  userID,
//		Title:   "我的第一篇博客",
//		Content: "这是博客内容...",
//		Tags:    []string{"技术", "编程"},
//	}
//
//	postID, err := postUtil.InsertOne(post)
//	if err != nil {
//		log.Printf("Failed to insert post: %v", err)
//	} else {
//		log.Printf("Inserted post with ID: %s", postID)
//	}
//
//	// 8. 监听集合变化
//	go func() {
//		err := postUtil.Watch(nil, func(changeDoc bson.M) {
//			log.Printf("Change detected: %v", changeDoc)
//		})
//		if err != nil {
//			log.Printf("Failed to watch collection: %v", err)
//		}
//	}()
//
//	// 保持程序运行
//	fmt.Println("Application is running. Press Ctrl+C to exit.")
//	select {}
//}
